home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / parser / ylib.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-17  |  21.4 KB  |  881 lines

  1. #define MAXPATHLEN 1024
  2.  
  3. #include <strings.h>
  4. #include <stdio.h>
  5. #include <pwd.h>
  6.  
  7. #include "utils/log.h"
  8. #include "catalogutils.h"
  9. #include "nodes/pg_lisp.h"
  10. #include "utils/exc.h"
  11. #include "utils/excid.h"
  12. #include "io.h"
  13. #include "utils/palloc.h"
  14. #include "parse_query.h"
  15. #include "catalog/pg_aggregate.h"
  16. #include "nodes/primnodes.h"
  17. #include "nodes/primnodes.a.h"
  18. #include "nodes/plannodes.h"
  19. #include "nodes/plannodes.a.h"
  20. #include "nodes/execnodes.h"
  21. #include "nodes/execnodes.a.h"
  22. #include "nodes/relation.h"
  23. #include "nodes/relation.a.h"
  24. #include "parser/parse.h"
  25. #include "parser/parsetree.h"
  26. #include "utils/builtins.h"
  27. #include "lib/lisplist.h"
  28.  
  29. RcsId("$Header: /private/postgres/src/parser/RCS/ylib.c,v 1.78 1992/07/10 15:48:15 mao Exp $");
  30.  
  31. LispValue parsetree;
  32.  
  33. #define DB_PARSE(foo) 
  34.  
  35. parser(str, l, typev, nargs)
  36.      char *str;
  37.      LispValue l;
  38.      ObjectId *typev;
  39.      int nargs;
  40. {
  41.     int yyresult;
  42.     void DeleteBuffer(void);
  43.  
  44.     init_io();
  45.  
  46.     /* Set things up to read from the string, if there is one */
  47.     if (strlen(str) != 0) {
  48.     StringInput = 1;
  49.     TheString = (char *) palloc(strlen(str) + 1);
  50.     bcopy(str,TheString,strlen(str)+1);
  51.     }
  52.  
  53.     parser_init(typev, nargs);
  54.     yyresult = yyparse();
  55.     DeleteBuffer();
  56.  
  57.     clearerr(stdin);
  58.       
  59.     if (yyresult) {    /* error */
  60.     CAR(l) = LispNil;
  61.     CDR(l) = LispNil;
  62.     return(-1);
  63.     }
  64.  
  65.     CAR(l) = CAR(parsetree);
  66.     CDR(l) = CDR(parsetree);
  67.  
  68.     if (parsetree == NULL) {
  69.     return(-1);
  70.     } else {
  71.     return(0);
  72.     }
  73. }
  74.  
  75. LispValue
  76. new_filestr ( filename )
  77.      LispValue filename;
  78. {
  79.   return (lispString (filename_in (CString(filename))));
  80. }
  81.  
  82. int
  83. lispAssoc ( element, list)
  84.      LispValue element, list;
  85. {
  86.     LispValue temp = list;
  87.     int i = 0;
  88.     if (list == LispNil) 
  89.       return -1; 
  90.     /* printf("Looking for %d", CInteger(element));*/
  91.  
  92.     while (temp != LispNil ) {
  93.     if(CInteger(CAR(temp)) == CInteger(element))
  94.       return i;
  95.     temp = CDR(temp);
  96.     i ++;
  97.     }
  98.        
  99.     return -1;
  100. }
  101.  
  102. LispValue
  103. parser_typecast ( expr, typename )
  104.      LispValue expr;
  105.      LispValue typename;
  106. {
  107.     /* check for passing non-ints */
  108.     Const adt;
  109.     Datum lcp;
  110.     Type tp;
  111.     char *type_string, *p, type_string_2[16];
  112.     int32 len;
  113.     char *cp = NULL;
  114.     char *const_string; 
  115.     bool string_palloced = false;
  116.  
  117.     type_string = CString(CAR(typename));
  118.     if (CDR(typename) != LispNil) {
  119.         *p = 0;
  120.         sprintf(type_string_2,"_%s", type_string);
  121.         tp = (Type) type(type_string_2);
  122.     } else {
  123.         tp = (Type) type(type_string);
  124.     }
  125.  
  126.     len = tlen(tp);
  127.  
  128.     switch ( CInteger(CAR(expr)) ) {
  129.       case 23: /* int4 */
  130.     const_string = (char *) palloc(256);
  131.     string_palloced = true;
  132.     sprintf(const_string,"%d", get_constvalue((Const)CDR(expr)));
  133.     break;
  134.  
  135.       case 19: /* char16 */
  136.     const_string = (char *) palloc(256);
  137.     string_palloced = true;
  138.     sprintf(const_string,"%s", get_constvalue((Const)CDR(expr)));
  139.     break;
  140.  
  141.       case 18: /* char */
  142.     const_string = (char *) palloc(256);
  143.     string_palloced = true;
  144.     sprintf(const_string,"%c", get_constvalue((Const)CDR(expr)));
  145.     break;
  146.  
  147.       case 701:/* float8 */
  148.     const_string = (char *) palloc(256);
  149.     string_palloced = true;
  150.     sprintf(const_string,"%f", get_constvalue((Const)CDR(expr)));
  151.     break;
  152.  
  153.       case 25: /* text */
  154.     const_string = DatumGetPointer(get_constvalue((Const)CDR(expr)));
  155.     const_string = (char *) textout((struct varlena *)const_string);
  156.     break;
  157.  
  158.       case 705: /* unknown */
  159.         const_string = DatumGetPointer(get_constvalue((Const)CDR(expr)));
  160.         const_string = (char *) textout((struct varlena *)const_string);
  161.         break;
  162.  
  163.       default:
  164.     elog(WARN,"unknown type %d", CInteger(CAR(expr)));
  165.     }
  166.  
  167.     cp = instr2 (tp, const_string);
  168.  
  169.     if (!tbyvalue(tp)) {
  170.     if (len >= 0 && len != PSIZE(cp)) {
  171.         char *pp;
  172.         pp = (char *) palloc(len);
  173.         bcopy(cp, pp, len);
  174.         cp = pp;
  175.     }
  176.     lcp = PointerGetDatum(cp);
  177.     } else {
  178.     switch(len) {
  179.       case 1:
  180.         lcp = Int8GetDatum(cp);
  181.         break;
  182.       case 2:
  183.         lcp = Int16GetDatum(cp);
  184.         break;
  185.       case 4:
  186.         lcp = Int32GetDatum(cp);
  187.         break;
  188.       default:
  189.         lcp = PointerGetDatum(cp);
  190.         break;
  191.     }
  192.     }
  193.     
  194.     adt = MakeConst ( typeid(tp), len, (Datum)lcp , 0, 0/*was omitted*/ );
  195.  
  196.     if (string_palloced)
  197.     pfree(const_string);
  198.  
  199.     return (lispCons(lispInteger(typeid(tp)), (LispValue)adt));
  200. }
  201.  
  202. LispValue
  203. parser_typecast2 ( expr, tp)
  204.      LispValue expr;
  205.      Type tp;
  206. {
  207.     /* check for passing non-ints */
  208.     Const adt;
  209.     Datum lcp;
  210.     int32 len = tlen(tp);
  211.     char *cp = NULL;
  212.  
  213.     char *const_string; 
  214.     bool string_palloced = false;
  215.     
  216.     switch ( CInteger(CAR(expr)) ) {
  217.       case 23: /* int4 */
  218.       const_string = (char *) palloc(256);
  219.       string_palloced = true;
  220.     sprintf(const_string,"%d",
  221.         get_constvalue((Const)CDR(expr)));
  222.     break;
  223.       case 19: /* char16 */
  224.       const_string = (char *) palloc(256);
  225.       string_palloced = true;
  226.     sprintf(const_string,"%s",
  227.         get_constvalue((Const)CDR(expr)));
  228.     break;
  229.       case 18: /* char */
  230.       const_string = (char *) palloc(256);
  231.       string_palloced = true;
  232.     sprintf(const_string,"%c",
  233.         get_constvalue((Const)CDR(expr)));
  234.     break;
  235.       case 701:/* float8 */
  236.     {
  237.         float64 floatVal = 
  238.         DatumGetFloat64(get_constvalue((Const)CDR(expr)));
  239.         const_string = (char *) palloc(256);
  240.         string_palloced = true;
  241.         sprintf(const_string,"%f", *floatVal);
  242.         break;
  243.     }
  244.       case 25: /* text */
  245.     const_string = 
  246.       DatumGetPointer(
  247.               get_constvalue((Const)CDR(expr)) );
  248.       const_string = (char *) textout((struct varlena *)const_string);
  249.     break;
  250.       case 705: /* unknown */
  251.         const_string =
  252.           DatumGetPointer(
  253.                           get_constvalue((Const)CDR(expr)) );
  254.           const_string = (char *) textout((struct varlena *)const_string);
  255.         break;
  256.       default:
  257.     elog(WARN,"unknown type%d ",
  258.          CInteger(CAR(expr)) );
  259.     }
  260.     
  261.     cp = instr2 (tp, const_string);
  262.     
  263.     
  264.     if (!tbyvalue(tp)) {
  265.     if (len >= 0 && len != PSIZE(cp)) {
  266.         char *pp;
  267.         pp = (char *) palloc(len);
  268.         bcopy(cp, pp, len);
  269.         cp = pp;
  270.     }
  271.     lcp = PointerGetDatum(cp);
  272.     } else {
  273.     switch(len) {
  274.       case 1:
  275.         lcp = Int8GetDatum(cp);
  276.         break;
  277.       case 2:
  278.         lcp = Int16GetDatum(cp);
  279.         break;
  280.       case 4:
  281.         lcp = Int32GetDatum(cp);
  282.         break;
  283.       default:
  284.         lcp = PointerGetDatum(cp);
  285.         break;
  286.     }
  287.     }
  288.     
  289.     adt = MakeConst ( (ObjectId)typeid(tp), (Size)len, (Datum)lcp , 0 , 0/*was omitted*/);
  290.     /*
  291.       printf("adt %s : %d %d %d\n",CString(expr),typeid(tp) ,
  292.       len,cp);
  293.       */
  294.     if (string_palloced) pfree(const_string);
  295.     return ((LispValue) adt);
  296. }
  297.  
  298. char *
  299. after_first_white_space( input )
  300.      char *input;
  301. {
  302.     char *temp = input;
  303.     while ( *temp != ' ' && *temp != 0 ) 
  304.       temp = temp + 1;
  305.  
  306.     return (temp+1);
  307. }
  308.  
  309. int 
  310. *int4varin( input_string )
  311.      char *input_string;
  312. {
  313.     int *foo = (int *)malloc(1024*sizeof(int));
  314.     register int i = 0;
  315.  
  316.     char *temp = input_string;
  317.     
  318.     while ( sscanf(temp,"%ld", &foo[i+1]) == 1 
  319.        && i < 1022 ) {
  320.     i = i+1;
  321.     temp = after_first_white_space(temp);
  322.     }
  323.     foo[0] = i;
  324.     return(foo);
  325. }
  326.  
  327. char *
  328. int4varout ( an_array )
  329.      int *an_array;
  330. {
  331.     int temp = an_array[0];
  332.     char *output_string = NULL;
  333.     extern int itoa();
  334.     int i;
  335.  
  336.     if ( temp > 0 ) {
  337.     char *walk;
  338.     output_string = (char *)malloc(16*temp); /* assume 15 digits + sign */
  339.     walk = output_string;
  340.     for ( i = 0 ; i < temp ; i++ ) {
  341.         itoa(an_array[i+1],walk);
  342.         printf ( "%s\n", walk );
  343.         while (*++walk != '\0')
  344.           ;
  345.         *walk++ = ' ';
  346.     }
  347.     *--walk = '\0';
  348.     }
  349.     return(output_string);
  350. }
  351.  
  352.  
  353. #define ADD_TO_RT(rt_entry)     p_rtable = nappend1(p_rtable,rt_entry) 
  354. extern List p_rtable;
  355. List
  356. ParseFunc ( funcname , fargs )
  357.      char *funcname;
  358.      List fargs;
  359. {
  360.     OID rettype = (OID)0;
  361.     OID funcid = (OID)0;
  362.     OID argrelid;
  363.     LispValue i = LispNil;
  364.     List first_arg_type = NULL;
  365.     Name relname, oldname;
  366.     Relation rd;
  367.     ObjectId relid;
  368.     int attnum;
  369.     int nargs;
  370.     Iter iter;
  371.     Func funcnode;
  372.     ObjectId oid_array[8];
  373.     OID argtype;
  374.     Param f;
  375.     int vnum;
  376.     LispValue retval;
  377.     LispValue setup_base_tlist();
  378.     bool retset;
  379.     bool exists;
  380.  
  381.     if (fargs)
  382.      {
  383.      if (CAR(fargs) == LispNil)
  384.        elog (WARN,"function %s does not allow NULL input",funcname);
  385.      first_arg_type = CAR(CAR(fargs));
  386.      }
  387.  
  388.     /*
  389.     ** check for projection methods: if function takes one argument, and 
  390.     ** that argument is a relation, param, or PQ function returning a complex 
  391.     ** type, then the function could be a projection.
  392.     */
  393.     if (length(fargs) == 1)
  394.      {
  395.      if (lispAtomp(first_arg_type) && CAtom(first_arg_type) == RELATION)
  396.       {
  397.           /* this is could be a projection */
  398.           relname = (Name) CString(CDR(CAR(fargs)));
  399.           if( RangeTablePosn ( relname ,LispNil ) == 0 )
  400.         ADD_TO_RT( MakeRangeTableEntry ((Name)relname,
  401.                         LispNil, 
  402.                         (Name)relname ));
  403.           oldname = relname;
  404.           relname = VarnoGetRelname(RangeTablePosn(oldname,0));
  405.           rd = heap_openr(relname);
  406.           relid = RelationGetRelationId(rd);
  407.           heap_close(rd);
  408.           if ((attnum = get_attnum(relid, (Name) funcname)) 
  409.           != InvalidAttributeNumber)
  410.         return((LispValue)(make_var(oldname, funcname)));
  411.           else        /* drop through */;
  412.       }
  413.      else if (ISCOMPLEX(CInteger(first_arg_type)) &&
  414.           IsA(CDR(CAR(fargs)),Iter) && 
  415.           (argrelid = typeid_get_relid
  416.            ((int)(argtype=funcid_get_rettype
  417.               (get_funcid((Func)(CAR(get_iterexpr((Iter)CDR(CAR(fargs)))))))))))
  418.       {
  419.           /* the argument is a function returning a tuple, so funcname
  420.          may be a projection */
  421.           if ((attnum = get_attnum(argrelid, (Name) funcname)) 
  422.           != InvalidAttributeNumber)
  423.            {
  424.            /* add a tlist to the func node and return the Iter */
  425.            rd = heap_openr(tname(get_id_type(argtype)));
  426.            if (RelationIsValid(rd))
  427.             {
  428.             relid = RelationGetRelationId(rd);
  429.             relname = RelationGetRelationName(rd);
  430.             heap_close(rd);
  431.             }
  432.            if (RelationIsValid(rd))
  433.             {
  434.             iter = (Iter)CDR(CAR(fargs));
  435.             set_func_tlist((Func)CAR(get_iterexpr(iter)), 
  436.                        setup_tlist(funcname, argrelid));
  437.             return(lispCons(lispInteger(att_typeid(rd,attnum)),iter));
  438.             }
  439.            else elog(WARN, 
  440.                  "Function %s has bad returntype %d", 
  441.                  funcname, argtype);
  442.            }
  443.           else        /* drop through */;
  444.       }
  445.      else if (ISCOMPLEX(CInteger(first_arg_type)) &&
  446.           IsA(CADR(CAR(fargs)),Func) && 
  447.           (argrelid = typeid_get_relid
  448.            ((int)(argtype=funcid_get_rettype
  449.               (get_funcid((Func)CADR(CAR(fargs))))))))
  450.       {
  451.           /* the argument is a function returning a tuple, so funcname
  452.          may be a projection */
  453.           if ((attnum = get_attnum(argrelid, (Name) funcname)) 
  454.           != InvalidAttributeNumber)
  455.            {
  456.            /* add a tlist to the func node */
  457.            rd = heap_openr(tname(get_id_type(argtype)));
  458.            if (RelationIsValid(rd))
  459.             {
  460.             relid = RelationGetRelationId(rd);
  461.             relname = RelationGetRelationName(rd);
  462.             heap_close(rd);
  463.             }
  464.            if (RelationIsValid(rd))
  465.             {
  466.             funcnode = (Func)CADR(CAR(fargs));
  467.             set_func_tlist(funcnode,
  468.                        setup_tlist(funcname, argrelid));
  469.             return(lispCons(lispInteger(att_typeid(rd,attnum)),
  470.                     CDR(CAR(fargs))));
  471.             }
  472.            else elog(WARN,
  473.                  "Function %s has bad returntype %d", 
  474.                  funcname, argtype);
  475.            }
  476.           else        /* drop through */;
  477.       }
  478.      else if (ISCOMPLEX(CInteger(first_arg_type)) &&
  479.           IsA(CADR(CAR(fargs)),Param))
  480.       {
  481.           /* If the Param is a complex type, this could be a projection */
  482.           f = (Param)CADR(CAR(fargs));
  483.           rd = heap_openr(tname(get_id_type(get_paramtype(f))));
  484.           if (RelationIsValid(rd)) 
  485.            {
  486.            relid = RelationGetRelationId(rd);
  487.            relname = RelationGetRelationName(rd);
  488.            heap_close(rd);
  489.            }
  490.           if (RelationIsValid(rd) && 
  491.           (attnum = get_attnum(relid, (Name) funcname))
  492.               != InvalidAttributeNumber)
  493.            {
  494.            set_param_tlist(f, setup_tlist(funcname, relid));
  495.            return(lispCons(lispInteger(att_typeid(rd, attnum)), f));
  496.            }
  497.           else        /* drop through */;
  498.       }
  499.      }
  500.  
  501.  
  502.     /*
  503.     ** If we dropped through to here it's really a function.
  504.     ** extract arg type info and transform relation name arguments into
  505.     ** varnodes of the appropriate form.
  506.     */
  507.  
  508.     bzero(&oid_array[0], 8 * sizeof(ObjectId));
  509.     nargs=0;
  510.  
  511.     foreach ( i , fargs ) 
  512.      {
  513.      List pair = CAR(i);
  514.      ObjectId toid;
  515.      
  516.      if (lispAtomp(CAR(pair)) && CAtom(CAR(pair)) == RELATION)
  517.       {
  518.           relname = (Name)CString(CDR(pair));
  519.  
  520.           /* get the range table entry for the var node */
  521.           vnum = RangeTablePosn(relname, 0);
  522.           if (vnum == 0) {
  523.           p_rtable = nappend1(p_rtable ,
  524.                       MakeRangeTableEntry(relname, 0, relname));
  525.           vnum = RangeTablePosn (relname, 0);
  526.           }
  527.  
  528.           /*
  529.            *  We have to do this because the relname in the pair
  530.            *  may have been a range table variable name, rather
  531.            *  than a real relation name.
  532.            */
  533.  
  534.           relname = (Name) VarnoGetRelname(vnum);
  535.  
  536.           rd = heap_openr(relname);
  537.           relid = RelationGetRelationId(rd);
  538.           heap_close(rd);
  539.           toid = typeid(type(relname));
  540.  
  541.           /*
  542.            *  for func(relname), the param to the function
  543.            *  is the tuple under consideration.  we build a special
  544.            *  VarNode to reflect this -- it has varno set to the correct
  545.            *  range table entry, but has varattno == 0 to signal that the
  546.            *  whole tuple is the argument.
  547.            */
  548.  
  549.           CAR(i) = (LispValue)
  550.         MakeVar(vnum, 0, toid,
  551.             lispCons(lispInteger(vnum),
  552.                  lispCons(lispInteger(0),LispNil)),
  553.             0 /* varslot */);
  554.       }
  555.      else
  556.       {
  557.           toid = CInteger(CAR(pair));
  558.           CAR(i) = CDR(pair);
  559.       }
  560.  
  561.      oid_array[nargs++] = toid;
  562.      }
  563.  
  564.     /*
  565.      *  func_get_detail looks up the function in the catalogs, does
  566.      *  disambiguation for polymorphic functions, handles inheritance,
  567.      *  and returns the funcid and type and set or singleton status of
  568.      *  the function's return value.  if func_get_detail returns true,
  569.      *  the function exists.  otherwise, there was an error.
  570.      */
  571.  
  572.     exists = func_get_detail(funcname, nargs, oid_array, &funcid,
  573.                  &rettype, &retset);
  574.     if (!exists)
  575.     elog(WARN, "no such attribute or function %s", funcname);
  576.  
  577.     /* got it */
  578.     funcnode = MakeFunc(funcid, rettype, false, 0, LispNil, 0, NULL, LispNil, LispNil);
  579.  
  580.     /*
  581.      *  for functons returning base types, we want to project out the
  582.      *  return value.  set up a target list to do that.  the executor
  583.      *  will ignore these for c functions, and do the right thing for
  584.      *  postquel functions.
  585.      */
  586.  
  587.     if (typeid_get_relid(rettype) == InvalidObjectId)
  588.     set_func_tlist(funcnode, (LispValue)setup_base_tlist(rettype));
  589.  
  590.     retval = lispCons((LispValue) funcnode, fargs);
  591.  
  592.     /*
  593.      *  if the function returns a set of values, then we need to iterate
  594.      *  over all the returned values in the executor, so we stick an
  595.      *  iter node here.  if it returns a singleton, then we don't need
  596.      *  the iter node.
  597.      */
  598.  
  599.     if (retset)
  600.     retval = (LispValue) MakeIter(retval);
  601.  
  602.     /* store type info in the return value for use by the type checker */
  603.     retval = lispCons (lispInteger(rettype), retval);
  604.  
  605.     return(retval);
  606. }
  607.  
  608. List
  609. ParseAgg(aggname, query, tlist)
  610.     char *aggname;
  611.     List query;
  612.     List tlist;
  613. {
  614.     int fintype;
  615.     OID AggId = (OID)0;
  616.     List list = LispNil;
  617.     char *keyword = "agg";
  618.     HeapTuple theAggTuple;
  619.     tlist = CADR(tlist);
  620.     if(!query)
  621.     elog(WARN,"aggregate %s called without arguments", aggname);
  622.     theAggTuple = SearchSysCacheTuple(AGGNAME, aggname, 0, 0, 0); 
  623.     AggId = (theAggTuple ? theAggTuple->t_oid : (OID)0);
  624.  
  625.     if(AggId == (OID)0) {
  626.        elog(WARN, "aggregate %s does not exist", aggname);
  627.     }
  628.     fintype = CInteger((LispValue)SearchSysCacheGetAttribute(AGGNAME,
  629.         AggregateFinalTypeAttributeNumber, aggname, 0, 0, 0));
  630.  
  631.     if(fintype != 0 ) {
  632.        list = (LispValue)
  633.      MakeList(lispInteger(fintype),lispName(keyword),lispName(aggname),
  634.           query,tlist,-1);
  635.     } else
  636.     elog(WARN, "aggregate %s does not exist", aggname);
  637.  
  638.     return (list);
  639. }
  640.  
  641.  
  642. /*
  643.  * RemoveUnusedRangeTableEntries
  644.  * - removes relations from the rangetable that are no longer
  645.  *   useful.  This helps in preventing the planner from generating
  646.  *   extra joins that are not needed.
  647.  */
  648.  
  649. /* XXX - not used yet
  650.  
  651. List
  652. RemoveUnusedRangeTableEntries ( parsetree )
  653.      List parsetree;
  654. {
  655.  
  656. }
  657. */
  658.  
  659. /* 
  660.  * FlattenRelationList
  661.  *
  662.  * at this point, time-qualified relation/relation-lists
  663.  * have a lispInteger in the front,
  664.  * inheritance relations have a lispString("*")
  665.  * in front
  666.  */ 
  667.  
  668.  
  669. #ifdef NOTYET
  670.  XXX - not used yet 
  671.  
  672. List
  673. FlattenRelationList ( rel_list )
  674.      List rel_list;
  675. {
  676.     List temp = NULL;
  677.     List possible_rtentry = NULL;
  678.  
  679.     foreach ( temp, rel_list ) {
  680.     possible_rtentry = CAR(temp);
  681.     
  682.     if ( consp ( possible_rtentry ) ) {
  683.  
  684.         /* can be any one of union, inheritance or timerange queries */
  685.         
  686.     } else {
  687.         /* normal entry */
  688.         
  689.     }
  690.     }
  691. }
  692.  
  693. #endif
  694.  
  695. List
  696. MakeFromClause ( from_list, base_rel )
  697.      List from_list;
  698.      LispValue base_rel;
  699. {
  700.     List i = NULL;
  701.     List j = NULL;
  702.     List k = NULL;
  703.     List flags = NULL;
  704.     List entry = NULL;
  705.     bool IsConcatenation = false;
  706.     List existing_varnos = NULL;
  707.     extern List RangeTablePositions();
  708.  
  709.     /* from_list will be a list of strings */
  710.     /* base_rel will be a wierd assortment of things, 
  711.        including timerange, inheritance and union relations */
  712.  
  713.     if ( length ( base_rel ) > 1 ) {
  714.     IsConcatenation = true;
  715.     }
  716.  
  717.     foreach ( i , from_list ) {
  718.         List temp = CAR(i);
  719.     
  720.     foreach ( j , base_rel ) {
  721.         List x = CAR(j);
  722.  
  723.         /* now reinitialize "flags" so that we don't 
  724.          * get inheritance or time range queries for
  725.          * relations that we didn't want them on 
  726.          */
  727.         
  728.         flags = lispCons(lispInteger(0),LispNil);
  729.         
  730.         if ( IsConcatenation == true ) {
  731.         flags = nappend1(flags, lispAtom("union"));
  732.         }
  733.         if ( ! null ( CADDR(x))) {
  734.         flags = nappend1(flags, lispAtom("inherits"));
  735.         }
  736.         
  737.         if ( ! null ( CADR(x))) {
  738.         /* set time range, if one exists */
  739.         CAR(flags) = CADR(x);
  740.         }
  741.         
  742.         existing_varnos = 
  743.           RangeTablePositions ( CString( CAR(x)), LispNil );
  744.         /* XXX - 2nd argument is currently ignored */
  745.         
  746.         if ( existing_varnos == NULL ) {
  747.         /* if the base relation does not exist in the rangetable
  748.          * as a virtual name, make a new rangetable entry
  749.          */
  750.         entry = (List)MakeRangeTableEntry ( (Name)CString ( CAR(x)),
  751.                            flags , 
  752.                            (Name)CString(temp));
  753.             ADD_TO_RT(entry);
  754.         } else {
  755.         /* XXX - temporary, should append the existing flags
  756.          * to the new flags or not ?
  757.          */
  758.         foreach(k,existing_varnos) {
  759.             int existing_varno = CInteger(CAR(k));
  760.             List rt_entry = nth ( existing_varno-1 , p_rtable );
  761.             if ( IsA(CAR(rt_entry),LispStr)) {
  762.             /* first time consing it */
  763.             CAR(rt_entry) = lispCons ( CAR(rt_entry) , 
  764.                           lispCons (temp,LispNil ));
  765.             } else {
  766.             /* subsequent consing */
  767.             CAR(rt_entry) = nappend1 ( CAR(rt_entry) , temp);
  768.             }
  769.             /* in either case, if no union flag exists, 
  770.              * cons one in
  771.              */
  772.             rt_flags (rt_entry) = nappend1 ( rt_flags(rt_entry),
  773.                             lispAtom("union"));
  774.         } /* foreach k */
  775.  
  776.         } /* if existing_varnos == NULL */
  777.  
  778.         /* NOTE : we dont' pfree old "flags" because they are
  779.          * really still present in the parsetree
  780.          */
  781.  
  782.       } /* foreach j */
  783.       } /* foreach i */
  784.  
  785.     return ( entry );
  786. }
  787.  
  788. /*
  789. ** HandleNestedDots --
  790. **    Given a nested dot expression (i.e. (relation func ... attr), build up
  791. ** a tree with of Iter and Func nodes.
  792. */
  793. LispValue HandleNestedDots(dots)
  794.      List dots;
  795. {
  796.     List mutator_iter;
  797.     LispValue retval = LispNil;
  798.  
  799.     if (IsA(CAR(dots),Param))
  800.       retval = 
  801.     ParseFunc(CString(CADR(dots)),
  802.           lispCons(MakeList
  803.                (lispInteger(get_paramtype((Param)CAR(dots))),
  804.                 CAR(dots), -1),
  805.                LispNil));
  806.     else
  807.       retval = ParseFunc(CString(CADR(dots)), 
  808.              lispCons(lispCons(lispAtom("relation"), 
  809.                        CAR(dots)),
  810.                   LispNil));
  811.  
  812.     foreach (mutator_iter, CDR(CDR(dots)))
  813.       retval = ParseFunc(CString(CAR(mutator_iter)), lispCons(retval, LispNil));
  814.  
  815.     return(retval);
  816. }
  817.  
  818. /*
  819. ** setup_tlist --
  820. **     Build a tlist that says which attribute to project to.
  821. **     This routine is called by ParseFunc() to set up a target list
  822. **     on a tuple parameter or return value.  Due to a bug in 4.0,
  823. **     it's not possible to refer to system attributes in this case.
  824. */
  825. LispValue setup_tlist(attname, relid)
  826.      Name attname;
  827.      ObjectId relid;
  828. {
  829.     TLE tle;
  830.     LispValue tlist;
  831.     Resdom resnode;
  832.     Var varnode;
  833.     ObjectId typeid;
  834.     int attno;
  835.  
  836.     attno = get_attnum(relid, attname);
  837.     if (attno < 0)
  838.     elog(WARN, "cannot reference attribute %s of tuple params/return values for functions", attname);
  839.  
  840.     typeid = find_atttype(relid, attname);
  841.     resnode = MakeResdom(1, typeid, ISCOMPLEX(typeid),
  842.              tlen(get_id_type(typeid)),
  843.              get_attname(relid, attno),
  844.              NULL    /* reskey   */,
  845.              NULL    /* reskeyop */,
  846.              0    /* resjunk  */);
  847.     varnode = MakeVar(-1, attno, typeid,
  848.               lispCons(lispInteger(-1),
  849.                    lispCons(lispInteger(attno),LispNil)),
  850.               0        /* varslot */);
  851.  
  852.     tle = (LispValue)MakeList(resnode, varnode, -1);
  853.     return(MakeList(tle, -1));
  854. }
  855.  
  856. /*
  857. ** setup_base_tlist --
  858. **    Build a tlist that extracts a base type from the tuple
  859. **    returned by the executor.
  860. */
  861. LispValue
  862. setup_base_tlist(typeid)
  863.     ObjectId typeid;
  864. {
  865.     TLE tle;
  866.     LispValue tlist;
  867.     Resdom resnode;
  868.     Var varnode;
  869.  
  870.     resnode = MakeResdom(1, typeid, ISCOMPLEX(typeid), 
  871.              tlen(get_id_type(typeid)),
  872.              (Name) "<noname>", NULL, NULL, 0);
  873.     varnode = MakeVar(-1, 1, typeid,
  874.             lispCons(lispInteger(-1),
  875.                  lispCons(lispInteger(1), LispNil)),
  876.             0);
  877.  
  878.     tle = (LispValue)MakeList(resnode, varnode, -1);
  879.     return (MakeList(tle, -1));
  880. }
  881.